package cz.cvut.fel.riak.loader.email;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cz.cvut.fel.riak.email.MIMEStatus;

public class PartNode {
	public enum TYPE {
		MULTIPART, DATA
	};

	private List<PartNode> multiParts = new ArrayList<PartNode>();
	private Map<String, String> headers = new HashMap<String, String>();
	private StringBuilder binaryData = new StringBuilder();
	private String contentType;
	private long size;
	private String key;
	private PartNode parent = null;
	private String boundary;
	private TYPE type = TYPE.DATA;
	
	
	/**
	 * @return the type
	 */
	public TYPE getType() {
		return type;
	}

	/**
	 * @param type the type to set
	 */
	public void setType(TYPE type) {
		this.type = type;
	}

	public PartNode(PartNode parent) {
		super();
		this.parent = parent;
	}

	public void addPart(PartNode node) {
		multiParts.add(node);
	}

	private void countKey() throws NoSuchAlgorithmException {
		MessageDigest md = MessageDigest.getInstance("SHA1");
		byte[] dataBytes = binaryData.toString().getBytes();
		md.update(dataBytes);

		key = md.digest().toString() + "" + dataBytes.length;
	}

	private void loadBoundary(String contentType) {
		if (contentType != null && contentType.length() > 0) {
			
			// throw new ParseException("Unable to determine content-type");
			if (contentType.contains("multipart")) {
				String tmpBound = contentType.toUpperCase();
				int from = tmpBound.indexOf("BOUNDARY=");

				boundary = contentType.substring(from+9);
				int to = boundary.indexOf(";");
				if (to > 0)
					boundary = boundary.substring(0, to);
				boundary = boundary.replace("\"", "").trim();

			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		String boundary = this.boundary;
		//this.boundary == null
		if ( parent != null) {
			boundary = "[PARENT] = "+this.parent.boundary;
		}
		
		int i = 0;
		PartNode p = this.parent;
		while (p != null) {
			i++;
			p = p.parent;
		}

		StringBuilder b = new StringBuilder();
		if (parent != null)
			b.append("Start: "+boundary+" => " + contentType + "\n");
		
		for (PartNode node : multiParts) {
			b.append(i + " " + node.toString() + "\n");
		}
		// b.append("End:"+contentType+"\n");
		return b.toString();
	}
	
	public boolean fillDeduplicationPlan(ArrayList<MIMEStatus> plan) {
		boolean doDeduplication = false;
		String boundary = this.boundary;		
		
		if ( parent != null) {
			boundary = this.parent.boundary;
		}
		
		if (this.contentType == null)
			return false;
		
		if (!this.contentType.toUpperCase().startsWith("TEXT") && !this.contentType.toUpperCase().startsWith("MULTIPART")) {
			doDeduplication = true;
		}
		
		if (this.parent != null)
			plan.add(new MIMEStatus(this.contentType,boundary,doDeduplication));
		
		for (PartNode node : multiParts) {
			 doDeduplication |= node.fillDeduplicationPlan(plan);
		}
		
		return doDeduplication;
		
	}

	public int getParts() {
		return multiParts.size();
	}

	public void setBoundary(String boundary) {
		this.boundary = boundary;
	}

	public String getBoundary() {
		return boundary;
	}

	public void setBinaryData(StringBuilder binaryData) {
		this.binaryData = binaryData;
	}

	public StringBuilder getBinaryData() {
		return binaryData;
	}

	public void setHeaders(Map<String, String> headers) {
		this.headers = headers;
	}

	public Map<String, String> getHeaders() {
		return headers;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
		loadBoundary(contentType);
	}

	public String getContentType() {
		return contentType;
	}

}
